package com.cc.gulimall.order.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.annotation.PostConstruct;

/**
 * <p>Title: MyRabbitConfig</p>
 * Description：配置序列化方式
 * date：2020/6/29 14:29
 */
@Slf4j
@Configuration
public class MyRabbitConfig {


    @Autowired
    private RabbitTemplate rabbitTemplate;

/*    @Primary
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        this.rabbitTemplate = rabbitTemplate;
        rabbitTemplate.setMessageConverter(messageConverter());
        initRabbitTemplate();
        return rabbitTemplate;
    }*/

    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }

    /**
     * 1.设置确认回调： ConfirmCallback
     * 先在配置文件中开启 publisher-confirms: true
     *
     * @PostConstruct: MyRabbitConfig对象创建完成以后 执行这个方法
     * <p>
     * 2.消息抵达队列的确认回调
     * 　	开启发送端消息抵达队列确认
     * publisher-returns: true
     * 只要抵达队列，以异步优先回调我们这个 returnconfirm
     * template:
     * mandatory: true
     * 3.消费端确认(保证每一个消息被正确消费才可以broker删除消息)
     * 1.默认是自动确认的 只要消息接收到 服务端就会移除这个消息
     * <p>
     * 如何签收:
     * 签收: channel.basicAck(deliveryTag, false);
     * 拒签: channel.basicNack(deliveryTag, false,true);
     * 配置文件中一定要加上这个配置
     * listener:
     * simple:
     * acknowledge-mode: manual
     */
    /*构造器创建完对象后调用本方法*/
    @PostConstruct
    public void initRabbitTemplate() {
        /**
         * 		设置确认回调
         *  correlationData: 消息的唯一id
         *  ack： 消息是否成功收到
         * 	cause：失败的原因
         */
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> log.info("\n收到消息: " + correlationData + "\tack: " + ack + "\tcause： " + cause));

        /**
         * 设置消息抵达队列回调：可以很明确的知道那些消息失败了.正确抵达队列不回调
         *
         * message: 投递失败的消息详细信息
         * replyCode: 回复的状态码
         * replyText: 回复的文本内容
         * exchange: 当时这个发送给那个交换机
         * routerKey: 当时这个消息用那个路由键
         */
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routerKey) -> log.error("Fail Message [" + message + "]" + "\treplyCode: " + replyCode + "\treplyText:" + replyText + "\texchange:" + exchange + "\trouterKey:" + routerKey));
    }
    /**
     * 消费端确认：
     * 默认消费端连上队列一收到所有消息后自动回复ack确认。但是代码中间拉闸了队列里的还没被业务成功处理的消息全被删了就
     * 我们可以设置手动确认，成功处理一个再确认一个
     */
}
